﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using OpenPhotoAlbum.DbAccess;

namespace OpenPhotoAlbum.BusinessLogics
{
    public class AlbumManager
    {
        #region Singleton

        private static readonly AlbumManager _instance = new AlbumManager();

        static AlbumManager() { }

        private AlbumManager() { }

        public static AlbumManager Instance
        {
            get { return _instance; }
        }

        #endregion

        public Album GetAlbum(DbLinqClassesDataContext context, Guid albumId)
        {
            var objects = from a in context.Albums
                          where a.AlbumId.Equals(albumId)
                          select a;
            if (objects != null && objects.Count() > 0)
            {
                return objects.First();
            }
            return null;
        }

        public Album GetAlbum(Guid albumId)
        {
            DbLinqClassesDataContext context = new DbLinqClassesDataContext();
            return GetAlbum(context, albumId);
        }

        public Guid CreateNewAlbum(Guid userId, string albumTitle, string albumDescription)
        {
            DbLinqClassesDataContext context = new DbLinqClassesDataContext();
            
            User user = UserManager.Instance.GetUser(context, userId);
            if (user == null) { return Guid.Empty; }
            
            Album album = new Album();
            album.AlbumId = Guid.NewGuid();
            album.AlbumTitle = albumTitle;
            album.AlbumDescription = albumDescription;
            album.AlbumCreationDate = DateTime.UtcNow;

            user.Albums.Add(album);
            context.SubmitChanges();

            return album.AlbumId;
        }

        public Guid DeleteAlbum(Guid albumId)
        {
            DbLinqClassesDataContext context = new DbLinqClassesDataContext();

            Album album = GetAlbum(context, albumId);
            if (album == null) { return Guid.Empty; }

            PhotoManager.Instance.DeletePhotos(context, album.Photos);

            context.Albums.DeleteOnSubmit(album);
            context.SubmitChanges();

            return album.AlbumId;
        }

        public IQueryable<Album> GetAlbums(DbLinqClassesDataContext context, Guid userId)
        {
            var objects = from a in context.Albums
                          where a.UserId.Equals(userId)
                          orderby a.AlbumCreationDate descending
                          select a;
            return objects;
        }

        public IQueryable<Album> GetAlbums(Guid userId)
        {
            DbLinqClassesDataContext context = new DbLinqClassesDataContext();
            return GetAlbums(context, userId);
        }

        public void UpdateAlbum(Guid albumId, string albumTitle, string albumDescription)
        {
            DbLinqClassesDataContext context = new DbLinqClassesDataContext();
            Album album = GetAlbum(context, albumId);
            album.AlbumTitle = albumTitle;
            album.AlbumDescription = albumDescription;
			album.AlbumModificationDate = DateTime.UtcNow;
            context.SubmitChanges();
        }

		public void UpdateAlbumTitle(Guid albumId, string title)
		{
			DbLinqClassesDataContext context = new DbLinqClassesDataContext();
			Album album = GetAlbum(context, albumId);
			album.AlbumTitle = title;
			album.AlbumModificationDate = DateTime.UtcNow;
			context.SubmitChanges();
		}

		public void UpdateAlbumDescription(Guid albumId, string description)
		{
			DbLinqClassesDataContext context = new DbLinqClassesDataContext();
			Album album = GetAlbum(context, albumId);
			album.AlbumDescription = description;
			album.AlbumModificationDate = DateTime.UtcNow;
			context.SubmitChanges();
		}

        public void UpdateModificationDate(DbLinqClassesDataContext context, Guid albumId)
        {
            Album album = GetAlbum(context, albumId);
			album.AlbumModificationDate = DateTime.UtcNow;
        }

        public void UpdateModificationDate(Guid albumId)
        {
            DbLinqClassesDataContext context = new DbLinqClassesDataContext();
            UpdateModificationDate(context, albumId);
            context.SubmitChanges();
        }

		public Guid GetUserId(Guid albumId)
		{
			if (albumId == null || albumId.Equals(Guid.Empty)) { return Guid.Empty; }

			DbLinqClassesDataContext context = new DbLinqClassesDataContext();
			var results = from album in context.Albums
						  where album.AlbumId.Equals(albumId)
						  select album.UserId;

			if (results == null || results.Count() != 1) { return Guid.Empty; }

			return results.First();
		}

		public User GetUser(Guid albumId)
		{
			if (albumId == null || albumId.Equals(Guid.Empty)) { return null; }

			DbLinqClassesDataContext context = new DbLinqClassesDataContext();
			var results = from album in context.Albums
						  where album.AlbumId.Equals(albumId)
						  select album.User;

			if (results == null || results.Count() != 1) { return null; }

			return results.Single();
		}

		public DateTime GetLastModificationDate(Guid albumId)
		{
			DbLinqClassesDataContext context = new DbLinqClassesDataContext();
			var results = from album in context.Albums
						  where album.AlbumId.Equals(albumId)
						  select album.AlbumModificationDate;
			DateTime? date = results.First();
			if (date.HasValue) { return date.Value; }
			else { return DateTime.MinValue; }
		}

		public Guid GetAlbumCover(Guid albumId)
		{
			DbLinqClassesDataContext context = new DbLinqClassesDataContext();

			// Look for user specified cover.
			var results = from photo in context.Photos
						  where photo.AlbumId.Equals(albumId) && photo.IsAlbumCover
						  select photo.PhotoId;
			if (results != null && results.Count() > 0) { return results.First(); }

			// Look for the first photo in target album.
			Album album = GetAlbum(context, albumId);
			if (album != null && album.Photos != null && album.Photos.Count() > 0)
				return album.Photos.First().PhotoId;

			// No photos...
			return Guid.Empty;
		}

		public int GetAlbumIndex(Guid userId, Guid albumId)
		{
			DbLinqClassesDataContext context = new DbLinqClassesDataContext();

			var ids = from a in context.Albums
						  where a.UserId.Equals(userId)
						  orderby a.AlbumCreationDate descending
						  select a.AlbumId;
			int index = 0;
			foreach (Guid id in ids)
			{
				if (id.Equals(albumId)) { return index; }
				index++;
			}
			return -1;
		}

		public void SetUnsetRecommendation(Guid albumId)
		{
			DbLinqClassesDataContext context = new DbLinqClassesDataContext();
			Album album = GetAlbum(context, albumId);
			album.Recommended = !album.Recommended;
			context.SubmitChanges();
		}

		public Album GetRecommendedAlbum()
		{
			DbLinqClassesDataContext context = new DbLinqClassesDataContext();
			var albums = from a in context.Albums
						 where a.Recommended == true
						 select a;
			if (albums == null || albums.Count() == 0) { return null; }

			Random rn = new Random();
			return albums.Skip(rn.Next(0, albums.Count())).First();
		}
	}

    public class FailedToCreateAlbumException : Exception { }
}
